OneSip 職務経歴書
from: 職務経歴書, Job History
2022.12–現在 OneSip LLC 業務委託
- 「Sake Discovery - OneSip」をApp Storeで
- iOS アプリの開発・UI/UX とインフラは全て一人で開発・保守している
- 業務委託契約ではあるものの単なる実装だけではなく、PO である Founder とプロダクト側も一緒に考えて二人三脚という形でサービスを使っている。
- iOS アプリの UI/UX も全て設計
- 業務経験は無かったので Apple 製アプリを中心に、似たサービスや個人的に好きな UI/UX を有するアプリを参考にしている。
- UI / UX を設計するのは非常に楽しいので、今後もやってみたい。
- とにかく楽しくて、これが本業になったらいいなぁと思っている。
- 利用技術 (v1.17.0 時点)
- 9 割程度 SwiftUI / 一部は UIKit
- Full swift-composable-architecture
- Xcode Cloud
- Swift Package Manager によるマルチモジュール (1 画面 1 モジュール)
- Infra 層は UI から依存しないよう DIP しており、SwiftUI の Preview 時にビルドされないようにしている: TCA で依存性を逆転させる
- Firebase (Auth, Analytics, Firestore, Storage, Cloud Functions, Cloud Messaging)
- Typesense (Firestore のデータを全文検索するために利用)
- Foursquare Places API を Venue 検索に利用
2022.12–2023.5 v1.0.0 リリースに向けた開発
- 別の業務委託が開発していた物をマルっと引き継ぎ
- 引き続き業務は無く、ソースコードと Firebase 環境をそのまま渡された形
- Founder から「どうにかリリースできる状態にして欲しい」という要望からお手伝いがスタート
- Founder の理解も得られ、「とりあえず機能を実装してリリースする」ではなく「現状のクリティカルな課題は解決してリリースする」を目指した
- クラッシュは無くす
- Firestore の微妙な設計は後に響くため、将来的な機能もある程度考慮して整理し直す
- 検索機能に使っていた Typesense が使えなくなっていたので実装し直す
- UI/UX 面で使いにくいものも一部直す
- 全体的に設計が練られていない状況だったのと UI は SwiftUI に置き換える予定のため、後々全て作り直す前提で、このタイミングでのリファクタリングは見送り
- 以下のような設計上の課題:
- 中途半端な Cocoa MVC
- 中途半端な抽象化
- DI の仕組みが無く、テストが書けない
- Service 層の一つ一つの凝集度が低く、複雑な実装になっている
- ちょうど Xcode Cloud のお試し期間だったので、このタイミングで CI/CD を導入
- 合わせて Test Flight の自動化を整備
- 本番環境と UAT 環境を別々に配信できるように環境整備
- Fastlane Match の導入 (後に Cloud managed certificate への移行に伴って廃止)
- このフェーズで得られた経験
- MVP アプリにおける、技術的な取捨選択
- どこまでは妥協しても今後のリファクタリングに影響しないか
- 何は前もって整備しておく必要があるか
- Xcode Cloud の実戦投入
- PO (Founder) との技術的負債をどう扱っていくかというコミュニケーション
- エンジニア側から見たリスクと修正にかかるコストの認識合わせを実施
- プロダクト側の要望や優先度、将来的に考えている機能をヒアリング
- 改めて修正優先度付けを実施
- Firebase と Typesense への理解
- Sign in with Apple の実装
- MVP アプリにおける、技術的な取捨選択
v1.0.1, v1.1.0, v1.2.0: SwiftUI / TCA への置き換えスタート
- ロジックがシンプル (状態が少ない) かつ枝葉の画面から置き換えスタート
- フォローしている / されているユーザ一覧画面
- ウィッシュリスト画面
- プロフィール編集画面
- プロフィール画面
- カテゴリーリスト画面
- Firestore との通信部分も TCA (swift-dependencies) の client 形式として作り直す
- TCA を採用した理由
- 一番の理由はやってみたかった・ガッツリ触ってみたかったから
- SwiftUI の状態管理手法として
ObservableObject
を利用した MVVM アーキテクチャの経験があったが、イマイチに感じていたからobjectWillChange
で全て再評価されてしまう- UIKit と違って SwiftUI は勝手に再描画してくれるので、ViewModel をかませる理由がより薄くなってしまった
- TCA であれば当時の
WithViewStore
によって選択的な状態監視が可能になる - 単一方向のデータフローを強制できることで Single source of truth を作りやすい
- Feature のテストが書きやすいことも魅力に感じた
v1.3.0
- TCA 1.0 にアップデート
- TCA が 1.0 になって対応したこと
- TCA は剥がすのが大変なので、できる限り最新をキャッチアップして、リリースされたら即対応できるようにしている。
- Issue / Discussion も頻繁に見ている。
- 日本酒だけでなく、酒造も Typesense 経由で検索できるようになった
- プロフィール画面でフォロー数、フォロワー数、ウィッシュリスト数が見れるようになった
v1.4.0
- Check-in を Share sheet によって共有できるようになった
- Check-in 詳細画面を追加した
- この辺りから完全新規画面を作るようになり、UI/UX の作成も行い始めた。
v1.5.0
- 開発基盤を整理した
- 以前は Xcode configuration / scheme によって本番と UAT を分けていたが、Xcode project ごと分けるようにした。
- 後々置き換える予定の TCA 化出来てないコードは
Deprecated
という Swift package を作ってそこに閉じ込めた- 残りの置き換え画面が分かりやすくなって、進捗把握やモチベーションアップに繋がった
@main
エントリーポイントと、Info.plist と言った一部のファイルを除いて、全ての実装が Swift Package に移った- Fastlane を廃止して自動署名 (Cloud managed certificate) に変更
- Check-in にいいねがつけられるようになった
- Firestore における 1:N や N:N のリレーションを考えるきっかけになった: Firestore における多対多のデータベース設計
v1.6.0
- ユーザーから日本酒追加のリクエストができるようなフォーム画面を作った
v1.7.0
- インクリメンタル検索を実装した
- 日本酒詳細画面を UI/UX から作り直した
v1.8.0
- Firebase Crashlytics の導入
- アクティビティ画面 (Check-in のタイムライン画面) を作り直した
v1.9.0
- Xcode 15 からの String Catalog をきっかけに日本語へのローカライズを始めた
- お問い合わせをネイティブ画面からメーラーの起動に切り替えた
- Push 通知機能の追加
- フォローされた時
- Check-in にいいねされた時
- 通知タップ時の画面遷移も実装
- Firestore + Function + Cloud Messaging で iOS アプリに Push 通知を送る
v1.10.0
- ローカル文字列に加えて、リモート情報のローカライズも始める
- 日本酒イベントを一覧できる機能の追加
- 日時情報、タイムゾーンを考慮するのが複雑だった
- 特に Firestore にどう情報を持たせるか
v1.11.0
- TCA を 1.4 から 1.5 にアップデート
- SwiftFormat の導入
- 日本酒イベント一覧を今日・明日・今週・今月といった特定の期間でフィルタリングできるようにした
v1.12.0
- プロフィール画面のリデザイン
- 全ユーザーのアクティビティ (Check-in) を見れるようにした
v1.13.0
- 枝葉の画面の TCA 化がかなり進んできたので、アプリ起動フローとなる根の部分も TCA 化した
- 画面遷移が当時は微妙だったので TCA Coordinators に頼った (後に
NavigationStack
が使えるようになって剥がした) - これで 100% TCA 移行完了した
- 画面遷移が当時は微妙だったので TCA Coordinators に頼った (後に
- SMV (Sake Meter Value) と酸度 (Acidity) の導入
v1.14.0
- Push 通知をタップした際に適切な画面に遷移するようにした: OneSip v1.14.0 Push 通知をタップしたら適切な画面に遷移する実装メモ
- フォロー通知: フォローしてくれたユーザーのプロフィール画面
- いいね通知: いいねされた Check-in 詳細画面
- フレーバータグを Check-in に含められるようにした
- SwiftUI の Layout プロトコルを触った
v1.15.0
- OneSip iOS 1.15.0 をリリースした
- どこで飲んだかという情報 (Venue) を Check-in に含められるようにした
- Foursquare Places API を利用
- TCA Coordinators を剥がした
- TCA の
Perception
(iOS 17 からのObservation
バックポート) に移行し始めた
v1.16.0
- Privacy manifest 対応
- 今まであまり日の目を浴びていなかった銘柄をより全面に押し出す機能を提供
- 銘柄を検索できるようにした
- 銘柄詳細画面の追加
v1.17.0
- 銘柄の評価点を算出するようにした
- その銘柄に属する日本酒に付けられた Check-in の評価点を平均している
- Firestore の aggregation query を利用している
- Light appearance への対応
- 今までは雰囲気のために Dark のみ対応していた
- SwiftUI の
foregroundStyle
modifier の優秀さに感動する
- 日本酒一覧のセルにも日本酒に付けられた Check-in 画像を表示
v1.18.0
- Check-in を行うための Floating action button をを追加した
- 今までのチェックインフローが他アプリと逆の操作だったため導入。
- よくあるアプリの体験: とりあえず投稿ボタンを押す → 投稿対象を選ぶ
- 今までの OneSip での体験: チェックインしたい日本酒を検索する → チェックインボタンを押す
- 初めて使う人にとってチェックイン機能がかなり深い階層にあって、中にはチェックイン機能自体に気付かずアンインストールする人もいそうと考えた。
- FAB の UI としては「つい押したくなる」ものを目指して、ニューモフィズムで作ってみた。
- FAB をタップすると、デフォルトで投稿の多い人気の日本酒がリストアップされ、キーワード検索で目当ての日本酒を探す流れにした。